From a1e0327056800aae0cf2e71b5c3fe0ca54ac7f65 Mon Sep 17 00:00:00 2001 From: Jimi Xenidis Date: Sun, 27 Aug 2006 16:12:00 -0400 Subject: [PATCH] [XEN][POWERPC] Allocate more memory than RMA for Dom0 The following patch will only effect Dom0 at the moment and allow it to be created with memory larger than RMA. It works by allocating extents (AKA chunks) of memory of an order specified by the processor. The extent size should be a value that is capabable of mapping a "large page" so we use the 970s large page size. These extents are tracked by an extents list that simply tracks these page allocations and what there mapping is. Other sub-systems effected by this: - Dom0 OFD devtree /memory cleanup - log_large_page_sizes is now an array - Config for minumum Dom0 size Caveats: - There is a hack around HTAB allocation because we currently allocate one at domain creation time, this will be correct by a patch to follow. - Dom0, or domains capable of mapping mfns byt have their extents be PFN=MFN Signed-off-by: Jimi Xenidis Signed-off-by: Hollis Blanchard --- xen/arch/powerpc/Makefile | 1 + xen/arch/powerpc/domain.c | 3 + xen/arch/powerpc/domain_build.c | 31 +++++++- xen/arch/powerpc/memory.c | 3 +- xen/arch/powerpc/mm.c | 75 +++++++++++++++++++ xen/arch/powerpc/ofd_fixup.c | 93 ++---------------------- xen/arch/powerpc/ofd_fixup_memory.c | 107 ++++++++++++++++++++++++++++ xen/arch/powerpc/oftree.h | 4 +- xen/arch/powerpc/powerpc64/ppc970.c | 22 ++++-- xen/include/asm-powerpc/config.h | 2 + xen/include/asm-powerpc/domain.h | 3 + xen/include/asm-powerpc/mm.h | 2 + xen/include/asm-powerpc/processor.h | 1 + 13 files changed, 246 insertions(+), 101 deletions(-) create mode 100644 xen/arch/powerpc/ofd_fixup_memory.c diff --git a/xen/arch/powerpc/Makefile b/xen/arch/powerpc/Makefile index c37a307f1c..09c52bc039 100644 --- a/xen/arch/powerpc/Makefile +++ b/xen/arch/powerpc/Makefile @@ -31,6 +31,7 @@ obj-y += mpic_init.o obj-y += of-devtree.o obj-y += of-devwalk.o obj-y += ofd_fixup.o +obj-y += ofd_fixup_memory.o obj-y += physdev.o obj-y += rtas.o obj-y += setup.o diff --git a/xen/arch/powerpc/domain.c b/xen/arch/powerpc/domain.c index fb7a5ed95a..8cb2eb7acb 100644 --- a/xen/arch/powerpc/domain.c +++ b/xen/arch/powerpc/domain.c @@ -114,6 +114,8 @@ int arch_domain_create(struct domain *d) } htab_alloc(d, htab_order_pages); + INIT_LIST_HEAD(&d->arch.extent_list); + return 0; } @@ -262,6 +264,7 @@ void sync_vcpu_execstate(struct vcpu *v) void domain_relinquish_resources(struct domain *d) { free_domheap_pages(d->arch.rma_page, d->arch.rma_order); + free_extents(d); } void arch_dump_domain_info(struct domain *d) diff --git a/xen/arch/powerpc/domain_build.c b/xen/arch/powerpc/domain_build.c index 3f18a0f101..3d5eefde73 100644 --- a/xen/arch/powerpc/domain_build.c +++ b/xen/arch/powerpc/domain_build.c @@ -30,6 +30,8 @@ #include #include "oftree.h" +#define log2(x) ffz(~(x)) + extern int parseelfimage_32(struct domain_setup_info *dsi); extern int loadelfimage_32(struct domain_setup_info *dsi); @@ -109,8 +111,10 @@ int construct_dom0(struct domain *d, struct domain_setup_info dsi; ulong dst; u64 *ofh_tree; + uint rma_nrpages = 1 << d->arch.rma_order; ulong rma_sz = rma_size(d->arch.rma_order); ulong rma = page_to_maddr(d->arch.rma_page); + uint htab_order; start_info_t *si; ulong eomem; int am64 = 1; @@ -151,13 +155,36 @@ int construct_dom0(struct domain *d, /* By default DOM0 is allocated all available memory. */ d->max_pages = ~0U; + /* default is the max(1/16th of memory, CONFIG_MIN_DOM0_PAGES) */ if (dom0_nrpages == 0) { - dom0_nrpages = 1UL << d->arch.rma_order; + dom0_nrpages = total_pages >> 4; + + if (dom0_nrpages < CONFIG_MIN_DOM0_PAGES) + dom0_nrpages = CONFIG_MIN_DOM0_PAGES; } + /* make sure we are at least as big as the RMA */ + if (dom0_nrpages < rma_nrpages) + dom0_nrpages = rma_nrpages; + else + dom0_nrpages = allocate_extents(d, dom0_nrpages, rma_nrpages); + d->tot_pages = dom0_nrpages; ASSERT(d->tot_pages > 0); + htab_order = log2(d->tot_pages) - 6; + if (d->arch.htab.order > 0) { + /* we incorrectly allocate this too early so lets adjust if + * necessary */ + printk("WARNING: htab allocated to early\n"); + if (d->arch.htab.order < htab_order) { + printk("WARNING: htab reallocated for more memory: 0x%x\n", + htab_order); + htab_free(d); + htab_alloc(d, htab_order); + } + } + ASSERT( image_len < rma_sz ); si = (start_info_t *)(rma_addr(&d->arch, RMA_START_INFO) + rma); @@ -276,7 +303,7 @@ int construct_dom0(struct domain *d, printk("DOM: pc = 0x%lx, r2 = 0x%lx\n", pc, r2); - ofd_dom0_fixup(d, *ofh_tree + rma, si, dst - rma); + ofd_dom0_fixup(d, *ofh_tree + rma, si); set_bit(_VCPUF_initialised, &v->vcpu_flags); diff --git a/xen/arch/powerpc/memory.c b/xen/arch/powerpc/memory.c index 9c5c55f686..0e7a20af84 100644 --- a/xen/arch/powerpc/memory.c +++ b/xen/arch/powerpc/memory.c @@ -64,8 +64,7 @@ static void set_max_page(struct membuf *mb, uint entries) } } -/* mark all memory from modules onward as unused, skipping hole(s), - * and returning size of hole(s) */ +/* mark all memory from modules onward as unused */ static void heap_init(struct membuf *mb, uint entries) { int i; diff --git a/xen/arch/powerpc/mm.c b/xen/arch/powerpc/mm.c index 56c6c045da..1ca8f9fda4 100644 --- a/xen/arch/powerpc/mm.c +++ b/xen/arch/powerpc/mm.c @@ -239,6 +239,69 @@ static int mfn_in_hole(ulong mfn) return 0; } +static uint add_extent(struct domain *d, struct page_info *pg, uint order) +{ + struct page_extents *pe; + + pe = xmalloc(struct page_extents); + if (pe == NULL) + return 0; + + pe->pg = pg; + pe->order = order; + pe->pfn = page_to_mfn(pg); + + list_add_tail(&pe->pe_list, &d->arch.extent_list); + + return pe->pfn; +} + +void free_extents(struct domain *d) +{ + /* we just need to free the memory behind list */ + struct list_head *list; + struct list_head *ent; + struct list_head *next; + + list = &d->arch.extent_list; + ent = list->next; + + while (ent != list) { + next = ent->next; + xfree(ent); + ent = next; + } +} + +uint allocate_extents(struct domain *d, uint nrpages, uint rma_nrpages) +{ + uint ext_order; + uint ext_nrpages; + uint total_nrpages; + struct page_info *pg; + + ext_order = cpu_extent_order(); + ext_nrpages = 1 << ext_order; + + total_nrpages = rma_nrpages; + + /* We only allocate in nr_extsz chunks so if you are not divisible + * you get more than you asked for */ + while (total_nrpages < nrpages) { + pg = alloc_domheap_pages(d, ext_order, 0); + if (pg == NULL) + return total_nrpages; + + if (add_extent(d, pg, ext_order) == 0) { + free_domheap_pages(pg, ext_order); + return total_nrpages; + } + total_nrpages += ext_nrpages; + } + + return total_nrpages; +} + int allocate_rma(struct domain *d, unsigned int order_pages) { ulong rma_base; @@ -266,6 +329,7 @@ ulong pfn2mfn(struct domain *d, long pfn, int *type) { ulong rma_base_mfn = page_to_mfn(d->arch.rma_page); ulong rma_size_mfn = 1UL << d->arch.rma_order; + struct page_extents *pe; if (pfn < rma_size_mfn) { if (type) @@ -280,6 +344,17 @@ ulong pfn2mfn(struct domain *d, long pfn, int *type) return pfn; } + /* quick tests first */ + list_for_each_entry (pe, &d->arch.extent_list, pe_list) { + uint end_pfn = pe->pfn + (1 << pe->order); + + if (pfn >= pe->pfn && pfn < end_pfn) { + if (type) + *type = PFN_TYPE_LOGICAL; + return page_to_mfn(pe->pg) + (pfn - pe->pfn); + } + } + /* This hack allows dom0 to map all memory, necessary to * initialize domU state. */ if (test_bit(_DOMF_privileged, &d->domain_flags)) { diff --git a/xen/arch/powerpc/ofd_fixup.c b/xen/arch/powerpc/ofd_fixup.c index e23c2ccd9f..e20978d9b1 100644 --- a/xen/arch/powerpc/ofd_fixup.c +++ b/xen/arch/powerpc/ofd_fixup.c @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Copyright (C) IBM Corp. 2005 + * Copyright (C) IBM Corp. 2005, 2006 * * Authors: Jimi Xenidis */ @@ -317,91 +317,6 @@ static ofdn_t ofd_rtas_props(void *m) } #endif -struct mem_reg { - u64 addr; - u64 sz; -}; - -static ofdn_t ofd_memory_chunk_create(void *m, ofdn_t p, - const char *ppath, - const char *name, - const char *dt, - ulong start, ulong size) -{ - struct mem_reg reg; - char path[128]; - ulong l; - u32 v; - ofdn_t n; - ulong nl = strlen(name) + 1; - ulong dtl = strlen(dt) + 1; - - l = snprintf(path, sizeof (path), "%s/%s@%lx", ppath, name, start); - n = ofd_node_add(m, p, path, l + 1); - ofd_prop_add(m, n, "name", name, nl); - - v = 1; - ofd_prop_add(m, n, "#address-cells", &v, sizeof (v)); - v = 0; - ofd_prop_add(m, n, "#size-cells", &v, sizeof (v)); - - ofd_prop_add(m, n, "device_type", dt, dtl); - - /* physical addresses usable without regard to OF */ - reg.addr = start; - reg.sz = size; - ofd_prop_add(m, n, "reg", ®, sizeof (reg)); - - return n; -} - -static ofdn_t ofd_memory_props(void *m, struct domain *d, ulong eoload) -{ - ofdn_t n = -1; - ulong start = 0; - static char name[] = "memory"; - ulong mem_size = rma_size(d->arch.rma_order); - ulong chunk_size = rma_size(d->arch.rma_order); - - /* Remove all old memory props */ - do { - ofdn_t old; - - old = ofd_node_find_by_prop(m, OFD_ROOT, "device_type", - name, sizeof(name)); - if (old <= 0) break; - - ofd_node_prune(m, old); - } while (1); - - while (start < mem_size) { - ulong size = (mem_size < chunk_size) ? mem_size : chunk_size; - - n = ofd_memory_chunk_create(m, OFD_ROOT, "", "memory", "memory", - start, size); - - if (start == 0) { - /* We are processing the first and RMA chunk */ - - /* free list of physical addresses available after OF and - * client program have been accounted for */ - struct mem_reg avail[] = { - /* 0 til OF @ 32MiB - 16KiB stack */ - { .addr = 0, .sz = ((32 << 20) - (16 << 10)) }, - /* end of loaded material to the end the chunk - 1 page */ - { .addr = eoload, .sz = chunk_size - eoload - PAGE_SIZE }, - /* the last page is reserved for xen_start_info */ - }; - ofd_prop_add(m, n, "available", &avail, - sizeof (avail)); - } - - start += size; - mem_size -= size; - } - return n; -} - static ofdn_t ofd_xen_props(void *m, struct domain *d, start_info_t *si) { ofdn_t n; @@ -442,7 +357,7 @@ static ofdn_t ofd_xen_props(void *m, struct domain *d, start_info_t *si) return n; } -int ofd_dom0_fixup(struct domain *d, ulong mem, start_info_t *si, ulong eoload) +int ofd_dom0_fixup(struct domain *d, ulong mem, start_info_t *si) { void *m; const ofdn_t n = OFD_ROOT; @@ -470,8 +385,8 @@ int ofd_dom0_fixup(struct domain *d, ulong mem, start_info_t *si, ulong eoload) printk("Add /chosen props\n"); ofd_chosen_props(m, (char *)si->cmd_line); - printk("fix /memory@0 props\n"); - ofd_memory_props(m, d, eoload); + printk("fix /memory props\n"); + ofd_memory_props(m, d); printk("fix /xen props\n"); ofd_xen_props(m, d, si); diff --git a/xen/arch/powerpc/ofd_fixup_memory.c b/xen/arch/powerpc/ofd_fixup_memory.c new file mode 100644 index 0000000000..6582938178 --- /dev/null +++ b/xen/arch/powerpc/ofd_fixup_memory.c @@ -0,0 +1,107 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (C) IBM Corp. 2006 + * + * Authors: Jimi Xenidis + */ + +#include +#include +#include +#include +#include "of-devtree.h" +#include "oftree.h" + +static char memory[] = "memory"; + +struct mem_reg { + u64 addr; + u64 sz; +}; + +static void ofd_memory_clean(void *m) +{ + ofdn_t old; + + /* Remove all old memory props */ + do { + old = ofd_node_find_by_prop(m, OFD_ROOT, "device_type", + memory, sizeof(memory)); + if (old <= 0) + break; + + ofd_node_prune(m, old); + } while (1); +} + +static ofdn_t ofd_memory_node_create( + void *m, ofdn_t p, const char *ppath, const char *name, + const char *dt, ulong start, ulong size) +{ + struct mem_reg reg; + char path[128]; + ulong l; + ofdn_t n; + ulong nl = strlen(name) + 1; + ulong dtl = strlen(dt) + 1; + + l = snprintf(path, sizeof (path), "%s/%s@%lx", ppath, name, start); + n = ofd_node_add(m, p, path, l + 1); + ofd_prop_add(m, n, "name", name, nl); + ofd_prop_add(m, n, "device_type", dt, dtl); + + /* physical addresses usable without regard to OF */ + reg.addr = start; + reg.sz = size; + ofd_prop_add(m, n, "reg", ®, sizeof (reg)); + + return n; +} + +static void ofd_memory_rma_node(void *m, struct domain *d) +{ + ulong size = rma_size(d->arch.rma_order); + ofdn_t n; + + n = ofd_memory_node_create(m, OFD_ROOT, "", memory, memory, 0, size); + BUG_ON(n <= 0); +} + +static void ofd_memory_extent_nodes(void *m, struct domain *d) +{ + ulong start; + ulong size; + ofdn_t n; + struct page_extents *pe; + + list_for_each_entry (pe, &d->arch.extent_list, pe_list) { + + start = pe->pfn << PAGE_SHIFT; + size = 1UL << (pe->order + PAGE_SHIFT); + + n = ofd_memory_node_create(m, OFD_ROOT, "", memory, memory, + start, size); + + BUG_ON(n <= 0); + } +} + +void ofd_memory_props(void *m, struct domain *d) +{ + ofd_memory_clean(m); + ofd_memory_rma_node(m, d); + ofd_memory_extent_nodes(m,d); +} diff --git a/xen/arch/powerpc/oftree.h b/xen/arch/powerpc/oftree.h index bf1f210665..f828e96c1a 100644 --- a/xen/arch/powerpc/oftree.h +++ b/xen/arch/powerpc/oftree.h @@ -26,8 +26,8 @@ extern ulong oftree; extern ulong oftree_len; extern ulong oftree_end; -extern int ofd_dom0_fixup( - struct domain *d, ulong mem, start_info_t *si, ulong dst); +extern int ofd_dom0_fixup(struct domain *d, ulong mem, start_info_t *si); +extern void ofd_memory_props(void *m, struct domain *d); extern int firmware_image_start[0]; extern int firmware_image_size[0]; diff --git a/xen/arch/powerpc/powerpc64/ppc970.c b/xen/arch/powerpc/powerpc64/ppc970.c index 70979df987..9c9d5c2b82 100644 --- a/xen/arch/powerpc/powerpc64/ppc970.c +++ b/xen/arch/powerpc/powerpc64/ppc970.c @@ -49,6 +49,10 @@ static struct rma_settings rma_orders[] = { { .order = 38, .rmlr0 = 0, .rmlr12 = 0, }, /* 256 GB */ }; +static uint log_large_page_sizes[] = { + 4 + 20, /* (1 << 4) == 16M */ +}; + static struct rma_settings *cpu_find_rma(unsigned int order) { int i; @@ -66,14 +70,20 @@ unsigned int cpu_default_rma_order_pages(void) unsigned int cpu_large_page_orders(uint *sizes, uint max) { - uint lp_log_size = 4 + 20; /* (1 << 4) == 16M */ - if (max < 1) - return 0; + uint i = 0; - sizes[0] = lp_log_size - PAGE_SHIFT; + while (i < max && i < ARRAY_SIZE(log_large_page_sizes)) { + sizes[i] = log_large_page_sizes[i] - PAGE_SHIFT; + ++i; + } - return 1; -} + return i; +} + +unsigned int cpu_extent_order(void) +{ + return log_large_page_sizes[0] - PAGE_SHIFT; +} void cpu_initialize(int cpuid) { diff --git a/xen/include/asm-powerpc/config.h b/xen/include/asm-powerpc/config.h index 1c081a90ff..bfa59ed3e5 100644 --- a/xen/include/asm-powerpc/config.h +++ b/xen/include/asm-powerpc/config.h @@ -47,6 +47,8 @@ extern char __bss_start[]; /* this should be per processor, but for now */ #define CACHE_LINE_SIZE 128 +/* 256M - 64M of Xen space seems like a nice number */ +#define CONFIG_MIN_DOM0_PAGES (192 << (20 - PAGE_SHIFT)) #define CONFIG_SHADOW 1 #define CONFIG_GDB 1 #define CONFIG_SMP 1 diff --git a/xen/include/asm-powerpc/domain.h b/xen/include/asm-powerpc/domain.h index 2d95c6a84b..6f21f6d5fe 100644 --- a/xen/include/asm-powerpc/domain.h +++ b/xen/include/asm-powerpc/domain.h @@ -38,6 +38,9 @@ struct arch_domain { struct page_info *rma_page; uint rma_order; + /* list of extents beyond RMA */ + struct list_head extent_list; + /* I/O-port access bitmap mask. */ u8 *iobmp_mask; /* Address of IO bitmap mask, or NULL. */ diff --git a/xen/include/asm-powerpc/mm.h b/xen/include/asm-powerpc/mm.h index fd2f0111f0..a3eeecf542 100644 --- a/xen/include/asm-powerpc/mm.h +++ b/xen/include/asm-powerpc/mm.h @@ -259,6 +259,8 @@ static inline unsigned long gmfn_to_mfn(struct domain *d, unsigned long gmfn) #define mfn_to_gmfn(_d, mfn) (mfn) extern int allocate_rma(struct domain *d, unsigned int order_pages); +extern uint allocate_extents(struct domain *d, uint nrpages, uint rma_nrpages); +extern void free_extents(struct domain *d); extern int steal_page(struct domain *d, struct page_info *page, unsigned int memflags); diff --git a/xen/include/asm-powerpc/processor.h b/xen/include/asm-powerpc/processor.h index 1c0d36d8ce..dbecadbdab 100644 --- a/xen/include/asm-powerpc/processor.h +++ b/xen/include/asm-powerpc/processor.h @@ -40,6 +40,7 @@ struct cpu_user_regs; extern void show_registers(struct cpu_user_regs *); extern void show_execution_state(struct cpu_user_regs *); extern void show_backtrace(ulong sp, ulong lr, ulong pc); +extern unsigned int cpu_extent_order(void); extern unsigned int cpu_default_rma_order_pages(void); extern uint cpu_large_page_orders(uint *sizes, uint max); extern void cpu_initialize(int cpuid); -- 2.30.2